<template>
  <div class="personalized-recommendations f fd-col w-100p h-100p">
    <n-scrollbar class="f fd-col f1 h-0">
      <loading-with-content
        :loading="pageData.loading"
        :class="['f fd-col', pageData.loading ? 'inset-0' : 'h-fit']"
        content-class="f fd-col pb-100"
        spin-class="custom-spin-without-icon spin-description-right"
      >
        <template #loading-icon><hamster-loader scale="0.8" /></template>
        <template #loading-description><span class="f-sz-14 ml--6">加载中...</span></template>
        <template #content>
          <n-carousel
            :interval="3000"
            :on-update:current-index="prevAndNextWatchDebouncedHandler"
            effect="card"
            centered-slides
            draggable
            show-arrow
            show-dots
            autoplay
            class="fs-0 banner-carousel"
            ref="carouselRef"
          >
            <n-carousel-item v-for="item in pageData.bannerData" :key="item.bannerId" ref="carouselItemRef">
              <lazy-loader>
                <div class="carousel-item-img-wrapper">
                  <img :src="item.pic" />
                  <span class="carousel-item-type-title f-sz-16">{{ item.typeTitle }}</span>
                </div>
              </lazy-loader>
            </n-carousel-item>
            <template #arrow="{ prev, next }">
              <span class="arrow-icon-prev arrow">
                <n-icon @click="prev" :color="arrowIconColor" :size="18" :component="ArrowBackIosNewSharp" />
              </span>
              <span class="arrow-icon-next arrow">
                <n-icon @click="next" :color="arrowIconColor" :size="18" :component="ArrowForwardIosSharp" />
              </span>
            </template>
          </n-carousel>
          <section v-for="(item, index) in pageData.sectionData" :key="index" class="f fd-col">
            <section-header :title="item.uiElement.subTitle.title" />
            <div v-if="item.showType === blockShowType['HOMEPAGE_SLIDE_PLAYLIST']" class="f fw-w mh--10 block-playlist-wrapper">
              <section-album
                v-for="(it, i) in item.creatives"
                :key="i"
                :main-title="it.uiElement.mainTitle.title"
                :src="it.uiElement.image.imageUrl"
                :tooltip-message="it.uiElement.mainTitle.title"
                :play-count="it.resourceExtInfo.playCount"
                @click="onAlbumClick(it.resourceId)"
                is-show-tooltip
              />
            </div>
            <div v-else-if="item.showType === blockShowType['HOMEPAGE_SLIDE_SONGLIST_ALIGN']" class="slide-songlist-wrapper">
              <n-carousel :loop="false" :slides-per-view="1" draggable touchable dot-type="line" class="slide-songlist-carousel">
                <n-carousel-item v-for="(it, i) in item.creatives.length" :key="i">
                  <div class="f mh--20">
                    <section-album
                      v-for="(subIt, subI) in item.creatives[it - 1]"
                      :key="subI"
                      :main-title="subIt.uiElement.mainTitle.title"
                      :src="subIt.uiElement.image.imageUrl"
                      :tooltip-message="subIt.uiElement.mainTitle.title"
                      :play-count="subIt.resourceExtInfo.playCount"
                      @click="onAlbumClick(subIt.resourceId)"
                      is-show-tooltip
                    />
                  </div>
                </n-carousel-item>
              </n-carousel>
            </div>
          </section>
        </template>
      </loading-with-content>
    </n-scrollbar>
  </div>
</template>

<script setup lang="ts">
  import { storeToRefs } from 'pinia';
  import { useRouter } from 'vue-router';
  import { useElementBounding, useWindowSize } from '@vueuse/core';
  import { useGlobalProperties } from '@/hooks/useGlobalProperties';
  import { useApi } from '@/hooks/useApi';
  import { useDesignSettingStoreOut } from '@/stores/modules/designSetting';
  import { ResultEnum } from '@/enums/httpEnum';
  import { ArrowBackIosNewSharp, ArrowForwardIosSharp } from '@vicons/material';
  import { blockCodeMapToTitle, blockShowType } from './constant';
  import SectionHeader from './components/section-header.vue';
  import SectionAlbum from './components/section-album.vue';
  import { INJECTION_SYMBOL_PANE_LENGTH_PERCENT, INJECTION_SYMBOL_CONTENT_PADDING } from '@/utils';
  import { debounce } from 'lodash-es';
  import { PageEnum } from '@/enums/pageEnum';

  interface ResetPageDataReturn {
    bannerData: any[];
    loading: boolean;
    sectionData: any[];
  }

  const router = useRouter();
  const { homePage: homePageApi } = useApi();
  // @ts-ignore
  const { $to, $message } = useGlobalProperties();
  const useDesignSettingStore = useDesignSettingStoreOut();
  const { getArticleConfig } = storeToRefs(useDesignSettingStore);
  const { width: windowWidth, height: windowHeight } = useWindowSize();

  const resetPageData: () => ResetPageDataReturn = () => ({ bannerData: [], sectionData: [], loading: false });

  const carouselRef = ref<ComponentPublicInstance | null>(null);
  const carouselItemRef = ref<ComponentPublicInstance[] | null>(null);
  const prevSlideTransform = ref('translateX(0) scale(0.7)');
  const nextSlideTransform = ref('translateX(0) scale(0.7)');
  const prevToEndDistance = ref(0);
  const nextToEndDistance = ref(0);
  const pageData = reactive(resetPageData());
  const paneLengthPercent = inject(INJECTION_SYMBOL_PANE_LENGTH_PERCENT, ref('50%'));
  const contentPadding = inject(INJECTION_SYMBOL_CONTENT_PADDING, ref('0'));
  const bannerStyle = computed(() => ({
    ...getArticleConfig.value?.banner,
  }));
  const dotBackgroundColor = computed(() => bannerStyle.value.dotBackgroundColor);
  const dotActiveBackgroundColor = computed(() => bannerStyle.value.dotActiveBackgroundColor);
  const arrowBackgroundColor = computed(() => bannerStyle.value.arrowBackgroundColor);
  const arrowIconColor = computed(() => bannerStyle.value.arrowIconColor);

  const onAlbumClick = async (id) => {
    if (!id) return;
    router.push({ name: PageEnum.MENU_PLAY_LIST_NAME, params: { id } });
  };

  const processingData = (data) => {
    const { blocks } = data;
    const sectionData = blocks
      .filter((item) => item.uiElement && item.creatives)
      .map((item) => {
        const showTypeFindIndex = Object.keys(blockShowType).findIndex((key) => key === item.showType);
        const newShowType = showTypeFindIndex > -1 ? blockShowType[item.showType] : item.showType;
        const homePageSlideList =
          newShowType === blockShowType['HOMEPAGE_SLIDE_PLAYLIST']
            ? (item.creatives || [])
                .map((item) => item.resources)
                .flat()
                .map((item) => ({ resourceId: item.resourceId, uiElement: item.uiElement, resourceExtInfo: item.resourceExtInfo }))
            : [];
        // 对于HOMEPAGE_BLOCK_PLAYLIST长度不足4的倍数时，截取到最大4的倍数
        const newCreatives =
          newShowType === blockShowType['HOMEPAGE_SLIDE_PLAYLIST']
            ? homePageSlideList.slice(0, Math.floor(homePageSlideList.length / 4) * 4)
            : (item.creatives || []).map((item) => item.resources);
        return { uiElement: item.uiElement, creatives: newCreatives, blockCode: item.blockCode, showType: newShowType };
      });
    // bannerData
    const { extInfo: { banners = [] } = {} } = blocks.find((item) => item.blockCode === blockCodeMapToTitle['bannerData']) || {};

    Object.assign(pageData, { bannerData: banners, sectionData });
  };

  const loadData = async () => {
    Object.assign(pageData, { loading: true });
    const [error, resp]: [any, any] = await $to(homePageApi.homepageInfo());
    Object.assign(pageData, { loading: false });
    if (error || resp.code !== ResultEnum.SUCCESS) {
      $message.error(error?.msg || resp?.msg || error);
    }
    if (resp && resp.code === ResultEnum.SUCCESS && resp.data) {
      processingData(resp.data);
      return;
    }
    Object.assign(pageData, resetPageData());
  };

  // swiper prev next距离两端计算
  const calcPrevAndNextCarouselItemDistanceToEnd = () => {
    const prevInstance = carouselItemRef.value!.find((instance: any) => instance.isPrev);
    const nextInstance = carouselItemRef.value!.find((instance: any) => instance.isNext);
    if (prevInstance && nextInstance) {
      const prevEl = prevInstance.$el;
      const nextEl = nextInstance.$el;
      const carousEl = carouselRef.value!.$el;
      const { x: carousElX, right: carousElRight } = useElementBounding(carousEl);
      const { x: prevElX } = useElementBounding(prevEl);
      const { right: nextElRight } = useElementBounding(nextEl);
      const prevToEnd = prevElX.value - carousElX.value;
      const nextToEnd = carousElRight.value - nextElRight.value;
      prevSlideTransform.value = `translateX(-${prevToEnd + prevToEndDistance.value}px) scale(0.7)`;
      nextSlideTransform.value = `translateX(${nextToEnd + nextToEndDistance.value}px) scale(0.7)`;
      // 记录最终位移量
      prevToEndDistance.value += prevToEnd;
      nextToEndDistance.value = nextToEnd + nextToEndDistance.value;
    }
  };

  const prevAndNextWatchDebouncedHandler = debounce((cv) => {
    // reset
    // prevSlideTransform.value = `translateX(0) scale(0.7)`;
    // nextSlideTransform.value = `translateX(0) scale(0.7)`;
    if (!!cv) {
      const timer = setTimeout(() => {
        calcPrevAndNextCarouselItemDistanceToEnd();
        clearTimeout(timer);
      }, 500);
    }
  }, 300);

  onMounted(loadData);

  watch(
    [carouselItemRef, paneLengthPercent, windowWidth, windowHeight],
    ([cv]) => {
      prevAndNextWatchDebouncedHandler(cv);
    },
    { immediate: true, flush: 'post' }
  );

  defineExpose({
    loadData,
  });
</script>

<style lang="scss">
  .personalized-recommendations {
    .content-wrapper {
      padding: v-bind(contentPadding);
      .n-carousel {
        &.banner-carousel {
          height: 266px;
          &:hover {
            .arrow {
              display: block;
            }
          }
          .arrow {
            position: absolute;
            // display: none;
            width: 30px;
            height: 30px;
            border-radius: 50%;
            background-color: v-bind(arrowBackgroundColor);
            text-align: center;
            cursor: pointer;
            &.arrow-icon-prev {
              left: 10px;
              bottom: 50%;
            }
            &.arrow-icon-next {
              right: 10px;
              bottom: 50%;
            }
          }
          .n-carousel__slide {
            height: 246px !important;
            width: 670px !important;
            border-radius: 10px !important;
            overflow: hidden;
            cursor: pointer;

            &--prev,
            &--next {
              opacity: 1 !important;
            }
            &--prev {
              transform: v-bind(prevSlideTransform) !important;
            }
            &--next {
              transform: v-bind(nextSlideTransform) !important;
            }

            .carousel-item-img-wrapper {
              position: relative;
              img {
                object-fit: cover;
              }

              .carousel-item-type-title {
                position: absolute;
                right: 10px;
                bottom: 30px;
                padding: 4px 8px;
                color: #666;
                border-radius: 6px;
                background-color: #fff;
              }
            }
          }
          .n-carousel__dots {
            left: 50% !important;
            bottom: 0 !important;
            transform: translateX(-50%) !important;
          }
        }
        &__dot {
          background-color: v-bind(dotBackgroundColor) !important;
          &--active {
            background-color: v-bind(dotActiveBackgroundColor) !important;
          }
        }
      }

      .block-playlist-wrapper {
        .section-album-wrapper {
          padding: 0 10px;
          flex: 0 1 25%;

          &:nth-child(n + 5) {
            margin-top: 16px;
          }
        }
      }

      .slide-songlist-wrapper {
        .section-album-wrapper {
          margin-bottom: 20px;
          padding: 0 20px;
          flex: 0 1 33.3%;
        }
      }
    }
  }
</style>
